/*
 * Copyright 2011 Romain Gilles
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jvdb;

import java.util.Map;
import java.util.Properties;

/**
 * load string configuration property with the following overriding order:
 * - Porperties Info
 * - Env
 * - VM Args
 */
class ConfigUtil {

    static final String LOGGER_BASE_NAME = "jvdb";

    /**
     * Global (Env/VM Args/Properties info) mandatory info used to specify the underlying driver as MySql, Sybase, Oracle...
     */
    static final String WRAPPED_DRIVER = "jvdb.driver";
    /**
     * Global (Env/VM Args/Properties info) optional info used to specify the logfile path.
     * If the logfile path is not specified the default one is used
     */
    static final String LOGFILE = "jvdb.logfile";

    /**
     * Global (Env/VM Args/Properties info) optional info used to specify if the {@code ResultSet} row fetch must be counted.
     * By default
     */
    static final String ENABLE_ROWCOUNT = "jvdb.rowcount";

    /**
     * Env or VM Args property optional used to specify if the console output has to be activated.
     * By default is {@code false}.
     */
    static final String ENABLE_CONSOLE = "jvdb.console";

    static final String ENABLE_PARSING = "jvdb.parse";

    static {
        ConfigChain configChain = new PropertiesConfigChain(System.getProperties(), null);
        configChain = new MapConfigChain(System.getenv(), configChain);
        BASE_CONFIG_CHAIN = configChain;
    }

    private static final ConfigChain BASE_CONFIG_CHAIN;
    private static final String DEFAULT_LOGFILE = "./jvdb.log";


    private ConfigUtil() {
    }

    static String getValue(String key, Properties info) {
        PropertiesConfigChain configChain = new PropertiesConfigChain(info, BASE_CONFIG_CHAIN);
        return (configChain).getValue(key);
    }

    //not yet used
    static String getValue(String key) {
        return BASE_CONFIG_CHAIN.getValue(key);
    }

    static boolean contains(String key) {
        return BASE_CONFIG_CHAIN.contains(key);
    }
    static boolean contains(String key, Properties info) {
        return new PropertiesConfigChain(info, BASE_CONFIG_CHAIN).contains(key);
    }
    private abstract static class ConfigChain {
        private ConfigChain successor;

        ConfigChain(ConfigChain successor) {
            this.successor = successor;
        }

        String getValue(String key) {
            String result = null;
            if (successor != null)
                result = successor.getValue(key);
            if (result == null && doContains(key))
                return doGetValue(key);
            return result;
        }

        boolean contains(String key) {
            return (successor != null && successor.contains(key)) || doContains(key);
        }

        abstract String doGetValue(String key);

        abstract boolean doContains(String key);
    }

    private static class MapConfigChain extends ConfigChain {
        private Map<String, String> map;

        private MapConfigChain(Map<String, String> map, ConfigChain successor) {
            super(successor);
            this.map = map;
        }

        @Override
        String doGetValue(String key) {
            return map.get(key);
        }

        @Override
        boolean doContains(String key) {
            return map.containsKey(key);
        }
    }

    private static class PropertiesConfigChain extends ConfigChain {
        private Properties properties;

        private PropertiesConfigChain(Properties properties, ConfigChain successor) {
            super(successor);
            this.properties = properties;
        }

        @Override
        String doGetValue(String key) {
            return properties.getProperty(key);  //To change body of implemented methods use File | Settings | File Templates.
        }

        @Override
        boolean doContains(String key) {
            return properties.containsKey(key);
        }
    }

    static String getLogfilePath() {
        String result = getValue(LOGFILE);
        return result != null ? result : DEFAULT_LOGFILE;
    }

    static String getWrappedDriver(Properties info) {
        return getValue(WRAPPED_DRIVER, info);
    }

    static boolean isConsoleEnable() {
        return contains(ENABLE_CONSOLE);
    }

    static boolean isSqlParsing(Properties info) {
        return contains(ENABLE_PARSING, info);
    }
}
